
/****************************************************************************/
/*Copyright (c) 2011, Florent DEVILLE.                                      */
/*All rights reserved.                                                      */
/*                                                                          */
/*Redistribution and use in source and binary forms, with or without        */
/*modification, are permitted provided that the following conditions        */
/*are met:                                                                  */
/*                                                                          */
/* - Redistributions of source code must retain the above copyright         */
/*notice, this list of conditions and the following disclaimer.             */
/* - Redistributions in binary form must reproduce the above                */
/*copyright notice, this list of conditions and the following               */
/*disclaimer in the documentation and/or other materials provided           */
/*with the distribution.                                                    */
/* - The names of its contributors cannot be used to endorse or promote     */
/*products derived from this software without specific prior written        */
/*permission.                                                               */
/* - The source code cannot be used for commercial purposes without         */ 
/*its contributors' permission.                                             */
/*                                                                          */
/*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS       */
/*"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT         */
/*LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS         */
/*FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE            */
/*COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,       */
/*INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,      */
/*BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;          */
/*LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER          */
/*CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT        */
/*LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN         */
/*ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE           */
/*POSSIBILITY OF SUCH DAMAGE.                                               */
/****************************************************************************/

#include "GeoVertex.h"
#include "OGLVisu.h"
#include <QGLWidget>
#include "GeoMesh.h"

//radius of the sphere representing a point
const float GeoVertex::_radius = 0.1;

//radius to the square of the sphere representing a point
const float GeoVertex::_squareRadius = GeoVertex::_radius * GeoVertex::_radius;

//diameter of the sphere representing a point
const float GeoVertex::_diameter = 2 * GeoVertex::_radius;

//constructor
GeoVertex::GeoVertex() : Geometry(GT_VERTEX), _mesh(0), _index(0)
{
	_translateMark = CVector3f();
}

//constructor
GeoVertex::GeoVertex(GeoMesh* mesh, int index):Geometry(GT_VERTEX), _mesh(mesh), _index(index)
{
	_translateMark = CVector3f();
}

//destructor
GeoVertex::~GeoVertex(){}

//determine if the point v is a point of the geometry object
bool GeoVertex::isGeometry(const CVector3f& v)const
{
	//get the point in local coordinate
	CMatrix transform = _mesh->getWorldMatrix();
	CVector3f localV = v * transform.inverse();

	//test if the point is inside the sphere
	CVector3f pos = _mesh->getVertexPosition(_index);
	CVector3f dist = localV - pos;
	float n2 = dist.norme2();
	if (n2 < _squareRadius + 0.1)
		return true;

	return false;
}

//test if the point v is on the mark of the primitive
bool GeoVertex::isTranslationMark(const CVector3f& v)
{
	//get the point in local coordinate
	CMatrix transform = _mesh->getWorldMatrix();
	CVector3f pos = _mesh->getVertexPosition(_index);
	CMatrix mpos;
	mpos.createTranslation(pos);
	transform = mpos * transform;

	CVector3f localV = v * transform.inverse();

	//get the world coorindates of the translation mark center
	CVector3f center = CVector3f(0, 0, 0) * transform;

	_hoover.x = 0;
	_hoover.y = 0;
	_hoover.z = 0;

	//get and test the distance between the point and the origin of the translation mark
	CVector3f distance = v - center;
	if(distance.norme2() > 1)
		return false;

	//get the point in the local coordinates of the translation mark
	distance = v * transform.inverse();
	distance.normalize();

	//text with the tree axis.
	CVector3f x(1, 0, 0);
	if(x.dot(distance) > 0.9f)
	{
		_hoover.x = 1;
		return true;
	}
	CVector3f y(0, 1, 0);
	if(y.dot(distance) > 0.9f)
	{
		_hoover.y = 1;
		return true;
	}
	CVector3f z(0, 0, 1);
	if(z.dot(distance) > 0.9f)
	{
		_hoover.z = 1;
		return true;
	}

	//v is not the mark
	return false;
}

//pre render function
void GeoVertex::preRender()
{
	//store current matrix
	glPushMatrix();

	//apply translation
	CVector3f translate = _mesh->getTranslate();
	glTranslatef(translate.x, translate.y, translate.z);
	
	//apply rotations
	CVector3f rotate = _mesh->getRotate();
	glRotatef(rotate.x, 1, 0, 0);

	glRotatef(rotate.y, 0, 1, 0);

	glRotatef(rotate.z, 0, 0, 1);

	//apply scale
	CVector3f scale = _mesh->getScale();
	glScalef(scale.x, scale.y, scale.z);

	//set vertex position
	glTranslatef(_translate.x, _translate.y, _translate.z);

	//apply material
	//Material material = _mesh->getMaterial();
	//glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, material.getAmbient());
	//glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, material.getDiffuse());
	//glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, material.getSpecular());
	//glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, material.getShininess());
}

//render the object
void GeoVertex::Render()
{
	glDisable(GL_LIGHTING);
	glColor3f(1, 1, 1);

	glPointSize(5);
	glBegin(GL_POINTS);
		glVertex3i(0, 0, 0);
	glEnd();

	glEnable(GL_LIGHTING);
}

//post render function
void GeoVertex::postRender()
{
	if (_selected)
		VISU.drawSelectionBox(_diameter, _diameter, _diameter);

	glPopMatrix();
}

//set the vertex position
void GeoVertex::setTranslate(const CVector3f& t)
{
	_mesh->setVertexPosition(_index, t);
	_translate = t;
	_mesh->updateAABB(_index);
	_mesh->calculateTrianglesNormal(_index);
}

//override setRotation to disable it
void GeoVertex::setRotation(const CVector3f& r){}

//override setScale to disable it
void GeoVertex::setScale(const CVector3f& s){}

//translate the object's position by the vector
void GeoVertex::translate(const CVector3f& t)
{
	CVector3f newPos = t + _mesh->getVertexPosition(_index);
	setTranslate(newPos);
}

//override rotate to disable it
void GeoVertex::rotate(const CVector3f& r){}

//override scale to disable it
void GeoVertex::scale(const CVector3f& s){}

//set the link between a vertex and a mesh
void GeoVertex::setInfo(GeoMesh* mesh, int id, const CVector3f& pos)
{
	_mesh = mesh;
	_index = id;
	_translate = pos;
}

//get the mesh owner of the vertex
GeoMesh* GeoVertex::getMesh()
{
	return _mesh;
}

//get the vertex id
int GeoVertex::getIndex()const
{
	return _index;
}

//delete the vertex in the mesh
void GeoVertex::deleteVertexInMesh()
{
	_mesh->deleteVertex(_index);
}

//draw the selected triangle
void GeoVertex::setSelectedTriangle(int triangleCount)const
{
	_mesh->setDrawSpecialTriangle(_index, triangleCount);
}

//get the number of triangle containing this vertex
int GeoVertex::getTriangleCount()const
{
	return _mesh->getTrianglesCount(_index);
}